/****************************************************************************
 *
 * Copyright (C) 2003-2008 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
package nfse;

import java.io.*;
import java.sql.Timestamp;
import java.util.zip.GZIPInputStream;

import nfse.gui.record.FlexRecord;
import nfse.gui.record.FlexRecordField;
import nfse.stats.StatsEntry;
import nfse.stats.StatsServer;

/*******************************************************************************
 * Net/FSERecord is a generic class which is extended by all Net/FSE event
 * types. It contains a variety of common methods, some abstract, that must be
 * implemented or overridden to reflect the differences in events supported by
 * Net/FSE.
 * 
 * @author bduphoff
 * 
 */
public abstract class NetFSERecord {

    /***************************************************************************
     * This switch tells Net/FSE that the record content can contain binary
     * information and needs to be converted into hex for storage in the dynamic
     * database.
     */
    public static boolean IS_BINARY = false;

    /***************************************************************************
     * The name of the type. Cannot contain spaces or special characters.
     * Example: Snort_IDS
     */
    protected String typeName = null;

    /***************************************************************************
     * The unique ID of the type associated with this record. Once an ID is used
     * by one type it cannot be used again.
     */
    protected int typeID = -1;

    /***************************************************************************
     * The sensor associated with this record.
     */
    private int sensorID = -1;

    /***************************************************************************
     * The line (or lines) of data sent to Net/FSE initially. This value will be
     * saved in Net/FSE so that records can be parsed at various stages.
     */
    private String initialString = "";

    /***************************************************************************
     * This field represents the date and time of the event/log. All events must
     * have a timestamp. In the case of records with durations, this field
     * should be used as the start timestamp.
     */
    private Timestamp timestamp;

    /***************************************************************************
     * This field represents the source IP address of the event/log as a long.
     * All events must have an IP address. A source address is nearly universal
     * so it is included in all events. This field and the srcAddr field should
     * always be set using the setSrcIP method.
     */
    private long srcIP;

    /***************************************************************************
     * This field represents the source IP address of the event/log as a dot
     * quad (e.g. 1.2.3.4). All events must have an IP address. A source address
     * is nearly universal so it is included in all events. This field and the
     * srcIP field should always be set using the setSrcIP method.
     */
    private String srcAddr;

    /***************************************************************************
     * This abstract method is the parser component of Net/FSE. Each event type
     * implements this function which returns a fully-parsed nfse.NetFSERecord.
     * 
     * @param line
     *            The String containing the unparsed event.
     * @param sensor
     *            The sensor from metadata.Sensors which corresponds to this
     *            event.
     * @return A NetFSERecord instance. Before returning a parsed event, the
     *         record must be cast back into a NetFSERecord.
     * @throws Exception
     *             Any parsing failure should throw some form of Exception which
     *             will be handled by the various Net/FSE components that parse
     *             events.
     */
    public abstract NetFSERecord generate(String line, int sensor) throws Exception;

    public void parse(String[] args, NetFSERecord rec) {
        try {

            File f = new File(args[0]);
            if (!f.exists()) {
                System.err.println("The file specified does not exist: '" + args[0] + "'.");
                throw (new Exception());
            }
            long count = 0;
            long bad = 0;
            long good = 0;
            long start = System.currentTimeMillis();
            if (f.getName().endsWith(".gz")) {
                GZIPInputStream in = new GZIPInputStream(new FileInputStream(f));
                String recordLine = rec.getRecordLine(in);
                while (recordLine != null) {
                    try {
                        count++;
                        NetFSERecord rec2 = rec.generate(recordLine, -1);
                        if (rec2 == null)
                            throw(new Exception("The record could not be parsed"));
                        good++;
                    } catch (Exception e) {
                        bad++;
                        
                        System.out.println("-- Start bad record --\n" + recordLine + "\n-- End bad record --");
                    }
                    recordLine = rec.getRecordLine(in);
                }
                in.close();
            } else {
                RandomAccessFile raf = new RandomAccessFile(f, "r");
                String recordLine = rec.getRecordLine(raf);
                while (recordLine != null) {
                    try {
                        count++;
                        NetFSERecord rec2 = rec.generate(recordLine, -1);
                        if (rec2 == null)
                            throw(new Exception("The record could not be parsed"));
                        good++;
                    } catch (Exception e) {
                        bad++;
                        e.printStackTrace();
                        System.out.println("-- Start bad record --\n" + recordLine + "\n-- End bad record --");
                    }
                    recordLine = rec.getRecordLine(raf);
                }
                raf.close();
            }
            long stop = System.currentTimeMillis();

            float sec = (float) ((stop - start) / 1000);
            if (sec == (float) 0.0)
                sec = (float) 1.0;

            System.out.println("       Records: " + NetFSEUtil.formattedInteger(count));
            System.out.println("  Good records: " + NetFSEUtil.formattedInteger(good));
            System.out.println("   Bad records: " + NetFSEUtil.formattedInteger(bad));
            System.out.println("       Seconds: " + NetFSEUtil.formattedDouble(sec));
            System.out.println("Records/Second: " + NetFSEUtil.formattedDouble(count / sec));

        } catch (Exception e) {
            System.err.println("Usage: java " + rec.getClass().getName() + " /data/file/path");
            System.err.println("\tThe data file can be raw logs or gzipped (ending in .gz)");
            // e.printStackTrace();
        }
    }

    public StatsEntry generateStats() {
        short protocol = (short) getProtocol();
        int dstPort = getDstPort();
        long dstIP = getDstIP();
        long srcIP = getSrcIP();

        long srcBytes = getSrcBytes();
        long dstBytes = getDstBytes();
        long srcPackets = getSrcPackets();
        long dstPackets = getDstPackets();

        // System.out.println(dstIP + ": " + NetFSE.isHomeNet(dstIP) + ", " +
        // srcIP + ": "
        // + NetFSE.isHomeNet(srcIP));

        short direction = StatsServer.DIRECTION_OUTGOING;

        boolean srcIsHome = false;
        boolean dstIsHome = false;

        if (srcIP != -1) {
            srcIsHome = NetFSE.isHomeNet(srcIP);
            if (srcIsHome)
                direction = StatsServer.DIRECTION_INCOMING;
            else
                direction = StatsServer.DIRECTION_OUTGOING;
        } else if (dstIP != -1) {
            dstIsHome = NetFSE.isHomeNet(dstIP);
            if (dstIsHome)
                direction = StatsServer.DIRECTION_OUTGOING;
            else
                direction = StatsServer.DIRECTION_INCOMING;
        }

        if (srcIsHome && dstIsHome) {
            direction = StatsServer.DIRECTION_INTERNAL;
        }

        StatsEntry stats = new StatsEntry();
        stats.sensorID = this.getSensorID();
        stats.startTS = this.getStartTS();
        stats.endTS = this.getEndTS();
        stats.direction = direction;
        stats.srcIP = srcIP;
        stats.dstIP = dstIP;
        stats.srcBytes = srcBytes;
        stats.dstBytes = dstBytes;
        stats.srcPackets = srcPackets;
        stats.dstPackets = dstPackets;
        stats.protocol = protocol;
        stats.dstPort = dstPort;

        return stats;
    }

    /***************************************************************************
     * This method is called when indexing event streams using the static b+
     * tree index implementation. It returns field values encoded as hex strings
     * which are used to the index the record.
     * 
     * @param field
     *            A field identifier from the nfse.NetFSE.FIELD_ types.
     * @return A hex-encoded value for the specified field. Returns an empty
     *         string ("") if the field specified is not supported by Net/FSE.
     *         Currently the following fields are supported: startts, srcip,
     *         dstip, dstport.
     */
    public String get(int field) {
        String temp = "";
        int len = 0;
        switch (field) {
        case (NetFSE.FIELD_START_TS):
            temp = Long.toHexString(getStartTS().getTime() / 1000);
            len = 8;
            break;
        case (NetFSE.FIELD_DST_IP):
            temp = Long.toHexString(getDstIP());
            len = 8;
            break;
        case (NetFSE.FIELD_SRC_IP):
            temp = Long.toHexString(getSrcIP());
            len = 8;
            break;
        case (NetFSE.FIELD_DST_PORT):
            temp = Integer.toHexString(getDstPort());
            len = 4;
            break;
        default:
            temp = null;
            break;
        }
        if (temp != null) {
            while (temp.length() < len)
                temp = "0" + temp;
        }
        return temp;
    }

    /***************************************************************************
     * Search results are stored in relational database tables, one for each
     * event type specified in a search. Each table contains columns for all
     * fields that are to be displayed in the web interface.
     * 
     * @param table
     *            The result table name into which records will be inserted
     *            following a search.
     * @return A CREATE TABLE SQL statement for the result table used to store
     *         search results for presentation in the web interface.
     */
    public abstract String getCreateFieldTableSQL(String table);

    /***************************************************************************
     * This method returns the field names in the event type as a comma
     * separated value String. Used in displaying the column names at the
     * beginning of a CSV file. This method can be overridden but the base
     * implementation calls getFlexRecordFields(), which is suitable in most
     * cases.
     * 
     * @return The event type field names as a CSV String.
     */
    public String getCSVColNames() {
        FlexRecordField[] fields = this.getFlexRecordFields();
        String colNames = "";
        for (int i = 0; i < fields.length; i++) {
            if (i > 0)
                colNames += ",";
            colNames += fields[i].columnName;
        }
        return colNames;
    }

    /***************************************************************************
     * Sometimes it is appropriate to have a human-readable type name, as the
     * real type name cannot contain spaces or special characters. This method
     * should be overridden when the type name is not suitable for display. If
     * this method is not overridden then the system type name is used.
     * 
     * @return The name of the type as it will be displayed for end users in the
     *         web interface.
     */
    public String getDisplayTypeName() {
        return getTypeName();
    }

    /***************************************************************************
     * This method returns the value of getDstIP() as a dot quad (e.g. 1.2.3.4).
     * 
     * @return The destination IP address as a dot quad String.
     */
    public String getDstAddr() {
        return NetFSEUtil.convertLongToIP(getDstIP());
    }

    /***************************************************************************
     * The base Net/FSE class does not have a destination IP address value so
     * this stub method returns -1, an invalid IP address. Event types with a
     * destination IP address must override this method and setDstIP() as well.
     * 
     * @return -1 (stub method)
     */
    public long getDstIP() {
        return -1;
    }

    /***************************************************************************
     * The base Net/FSE class does not have a destination port value so this
     * stub method returns -1, an invalid port. Event types with a destination
     * port must override this method.
     * 
     * @return -1 (stub method)
     */
    public int getDstPort() {
        return -1;
    }

    /***************************************************************************
     * The base Net/FSE class does not have a source port value so this stub
     * method returns -1, an invalid port. Event types with a destination port
     * must override this method.
     * 
     * @return -1 (stub method)
     */
    public int getSrcPort() {
        return -1;
    }

    /***************************************************************************
     * The base Net/FSE class does not have a end timestamp value so this stub
     * method returns the value of the start timestamp by calling getStartTS().
     * Event types with a duration must override this method.
     * 
     * @return -1 (stub method)
     */
    public Timestamp getEndTS() {
        return getStartTS();
    }

    /***************************************************************************
     * This method transforms the parsed event into a FlexRecord for use in
     * displaying the record in the web interface. This method is abstract and
     * therefore must be implemented by each individual event type.
     * 
     * @return The event in the form of a nfse.gui.record.FlexRecord that can be
     *         passed to the web interface.
     */
    public abstract FlexRecord getFlexRecord();

    /***************************************************************************
     * This method transforms the parsed event into an array of FlexRecordFields
     * that contains information on column names, types and display criteria.
     * This method is abstract and therefore must be implemented by each
     * individual event type extending NetFSERecord.
     * 
     * @return The event type information in the form of a
     *         nfse.gui.record.FlexRecordField array that can be passed to the
     *         web interface.
     */
    public abstract FlexRecordField[] getFlexRecordFields();

    /***************************************************************************
     * This method defines which fields are to be indexed by Net/FSE for the
     * event type. This stub method will cause Net/FSE to index events on
     * startts and srcip. It should be overridden in cases where there are
     * additional fields to index.
     * 
     * @return An integer array of NetFSE.FIELD_ values.
     */
    public int[] getIndexedFields() {
        int[] temp = { NetFSE.FIELD_START_TS, NetFSE.FIELD_SRC_IP };
        return temp;
    }

    /***************************************************************************
     * This method is called to index search result tables in the results
     * database. The fields indexed are taken from getFlexRecordFields(). This
     * method is not typically overridden.
     * 
     * @param table
     *            The table name of the result table that is to be indexed.
     * @return A String array of SQL CREATE INDEX statements.
     */
    public String[] getIndexFieldTableSQL(String table) {
        FlexRecordField[] fields = this.getFlexRecordFields();
        String[] temp = new String[fields.length];
        for (int i = 0; i < fields.length; i++)
            temp[i] = "create index " + table + "_" + fields[i].columnName + "_idx on " + table + " ("
                    + fields[i].columnName + ")";
        return temp;
    }

    /***************************************************************************
     * This method is called when inserting records into the results database
     * following a search.
     * 
     * @param id
     *            The record ID to use for this entry. This value may become
     *            unnecessary in future versions.
     * @param table
     *            The table in the results database that this record will be
     *            inserted into.
     * @return An SQL INSERT statement for this event instance.
     */
    public abstract String getInsertFieldTableSQL(int id, String table);

    /***************************************************************************
     * The base Net/FSE class does not have a protocol value so this stub method
     * returns -1, an invalid protocol. Event types with a protocol must
     * override this method.
     * 
     * @return -1 (stub method)
     */
    public int getProtocol() {
        return -1;
    }

    /***************************************************************************
     * The base Net/FSE class does not have a destination bytes value so this
     * stub method returns -1, an invalid byte count. Event types with byte
     * information must override this method.
     * 
     * @return -1 (stub method)
     */
    public long getDstBytes() {
        return -1;
    }

    /***************************************************************************
     * The base Net/FSE class does not have a source bytes value so this stub
     * method returns -1, an invalid byte count. Event types with byte
     * information must override this method.
     * 
     * @return -1 (stub method)
     */
    public long getSrcBytes() {
        return -1;
    }

    /***************************************************************************
     * The base Net/FSE class does not have a destination packets value so this
     * stub method returns -1, an invalid packet count. Event types with packet
     * count information must override this method.
     * 
     * @return -1 (stub method)
     */
    public long getDstPackets() {
        return -1;
    }

    /***************************************************************************
     * The base Net/FSE class does not have a source packets value so this stub
     * method returns -1, an invalid packet count. Event types with packet count
     * information must override this method.
     * 
     * @return -1 (stub method)
     */
    public long getSrcPackets() {
        return -1;
    }

    /***************************************************************************
     * This method will return a single-line event from a gzipped data stream.
     * Bytes are read until the '\n' character is read. This method is
     * appropriate for any event type whose records are written on single lines.
     * Multi-line records need to override this function.
     * 
     * @param dataIn
     *            The gzipped data stream (ultimately a file) from which events
     *            are being read and parsed.
     * @return The unparsed event as a String.
     */
    public String getRecordLine(GZIPInputStream dataIn) {
        try {
            StringBuffer line = new StringBuffer();
            int ch = 0;
            do {
                ch = dataIn.read();
                line.append((char) ch);

            } while ((ch != -1) && ((char) ch != '\n'));
            return line.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***************************************************************************
     * This method will return a single-line event from a RandomAccessFile using
     * the readLine() method. This method is appropriate for any event type
     * whose records are written on single lines. Multi-line records need to
     * override this function.
     * 
     * @param dataIn
     *            The file from which events are being read and parsed.
     * @return The unparsed event as a String.
     */
    public String getRecordLine(RandomAccessFile dataIn) {
        try {
            String line = dataIn.readLine();
            return line;
        } catch (Exception e) {

        }
        return null;
    }

    /***************************************************************************
     * This method returns the value of getSrcIP() as a dot quad (e.g. 1.2.3.4).
     * 
     * @return The source IP address as a dot quad String.
     */
    public String getSrcAddr() {
        return NetFSEUtil.convertLongToIP(getSrcIP());
    }

    /***************************************************************************
     * The NetFSERecord base type assumes that each event type has a source IP
     * address. This is typically the case and this method can be used in
     * conjunction with setSrcIP() without modification for most event types.
     * However, these methods should be overridden in the rare case that an
     * event does not have a source IP address.
     * 
     * @return The source IP address as a long.
     */
    public long getSrcIP() {
        return srcIP;
    }

    /***************************************************************************
     * The NetFSERecord base type assumes that each event type has a start
     * timestamp. This is typically the case and this method can be used in
     * conjunction with setStartTS() without modification for most event types.
     * Net/FSE does not currently support even types that do not have some form
     * of start timestamp.
     * 
     * @return The start timestamp as a java.sql.Timestamp.
     */
    public Timestamp getStartTS() {
        return getTimestamp();
    }

    /***************************************************************************
     * This method will index all fields returned by getIndexedFields() and is
     * called when creating new dynamic tables in nfse.DataSocket.
     * 
     * @param table
     *            The name of the table to create the index statements for.
     * @return A String array of CREATE INDEX statements for the fields being
     *         indexed by Net/FSE.
     */
    public String[] getTempIndexSQL(String table) {
        int[] fields = this.getIndexedFields();
        String[] temp = new String[fields.length];
        for (int i = 0; i < temp.length; i++) {
            temp[i] = "create index " + table + "_" + NetFSE.FIELD_NAMES[fields[i]] + "_idx on " + table + " ("
                    + NetFSE.FIELD_NAMES[fields[i]] + ")";
        }
        return temp;
    }

    /***************************************************************************
     * This method creates the insert SQL statement for the event instance based
     * on the fields returned by getIndexedFields(). This method is called in
     * nfse.DataSocket.insertDynamic() when an event is to be inserted in the
     * dynamic database.
     * 
     * This method can be overridden for optimization in high-volume event types
     * but is sufficient as is in most cases. The primary overhead of this
     * method is repeated calls to getIndexedFields() where a single call is
     * sufficient.
     * 
     * @param table
     *            The table name where this event is going to be inserted.
     * @return An SQL INSERT statement for this event instance. The INSERT INTO
     *         TABLE portion is not added here to save memory but is added when
     *         nfse.DataSocket.purgeRecords() is called.
     */
    public String getTempInsertSQL() {
        StringBuffer temp = new StringBuffer("(");
        int[] fields = this.getIndexedFields();
        for (int i = 0; i < fields.length; i++) {
            switch (fields[i]) {
            case (NetFSE.FIELD_START_TS):
                temp.append("'" + getStartTS() + "'");
                break;
            case (NetFSE.FIELD_SRC_IP):
                if (getSrcIP() != -1)
                    temp.append("'" + getSrcAddr() + "'");
                else
                    temp.append("null");
                break;
            case (NetFSE.FIELD_DST_IP):
                if (getDstIP() != -1)
                    temp.append("'" + getDstAddr() + "'");
                else
                    temp.append("null");
                break;
            case (NetFSE.FIELD_DST_PORT):
                temp.append(getDstPort());
                break;
            default:
                break;
            }
            temp.append(",");
        }

        if (hasBinary()) {
            temp.append("'','");
            temp.append(NetFSEUtil.convertToHex(toRecord()));
            temp.append("'");
        } else {
            temp.append("'");
            temp.append(toRecord().replaceAll("'", " "));
            temp.append("',''");
        }
        temp.append(")");
        // System.out.println(temp.toString());
        return temp.toString();
    }

    /***************************************************************************
     * This method will generate a CREATE TABLE SQL statement for this event
     * type. All fields returned by getIndexedFields() are added to the table.
     * It is called when creating new dynamic tables in nfse.DataSocket.
     * 
     * @param table
     *            The name of the table to create.
     * @return A CREATE TABLE statement for the fields being indexed by Net/FSE.
     */
    public String getTempTableSQL(String table) {
        StringBuffer temp = new StringBuffer("create table ");
        temp.append(table);
        temp.append("(");
        int[] fields = this.getIndexedFields();
        for (int i = 0; i < fields.length; i++) {
            switch (fields[i]) {
            case (NetFSE.FIELD_START_TS):
                temp.append("startts timestamp");
                break;
            case (NetFSE.FIELD_SRC_IP):
                temp.append("srcip inet");
                break;
            case (NetFSE.FIELD_DST_IP):
                temp.append("dstip inet");
                break;
            case (NetFSE.FIELD_DST_PORT):
                temp.append("dstport int");
                break;
            default:
                break;
            }
            temp.append(",");
        }

        temp.append("record text");
        temp.append(",");
        temp.append("record_hex text");
        temp.append(") ");
        // System.out.println(temp.toString());
        return temp.toString();
    }

    /***************************************************************************
     * Gets the unique type ID for this event type. This value is specified in
     * the Net/FSE configuration process (see nfse.NetFSEServer.conifgure()).
     * 
     * @return The unique event type ID.
     */
    public int getTypeID() {
        return typeID;
    }

    /***************************************************************************
     * Gets the unique type name for this event type. This value is specified in
     * the Net/FSE configuration process (see nfse.NetFSEServer.conifgure()).
     * 
     * @return The unique event type name.
     */
    public String getTypeName() {
        return typeName;
    }

    /***************************************************************************
     * This method can be overridden depending on if the event type contains
     * binary data. It should return true is this is the case, instead of the
     * default of false returned by this stub method.
     * 
     * @return The IS_BINARY field.
     */
    public boolean hasBinary() {
        return IS_BINARY;
    }

    /***************************************************************************
     * This method performs no operation by default. It should be overridden by
     * event type implementations with destination IP addresses and should set
     * the values of dstIP and dstAddr.
     * 
     */
    public void setDstIP(long dstIP) {
        // no op
    }

    /***************************************************************************
     * This method sets the srcIP and srcAddr fields based on the IP passed in
     * (as a long). Not typically overridden except in the rare case that there
     * is no source IP.
     * 
     * @param srcIP
     *            The source IP address as a 32-bit long.
     */
    public void setSrcIP(long srcIP) {
        this.srcIP = srcIP;
        this.srcAddr = NetFSEUtil.convertLongToIP(srcIP);
    }

    /***************************************************************************
     * Sets the timestamp field. All Net/FSE event types must have a timestamp
     * of some sort.
     * 
     * @param startTS
     */
    public void setStartTS(Timestamp startTS) {
        this.setTimestamp(startTS);
    }

    /***************************************************************************
     * This method returns the fields in the event type as a comma separated
     * value String. This method can be overridden but the base implementation
     * calls getFlexRecordFields(), which is suitable in most cases.
     * 
     * @return The event type as a CSV String.
     */
    public String toCSV() {
        String temp = "";
        FlexRecord flex = getFlexRecord();
        for (int i = 0; i < flex.values.length; i++) {
            if (i > 0)
                temp += ",";
            temp += flex.values[i];
        }
        return temp;
    }

    /***************************************************************************
     * Returns the initial, unparsed String value for this event type. Should
     * not be overridden.
     * 
     * @return The unparsed String that was sent initially to Net/FSE.
     */
    public String toRecord() {
        return getInitialString();
    }

    /***************************************************************************
     * Displays the event as a CSV by calling toCSV(). Can be overridden in
     * cases where a CSV representation is not desirable.
     * 
     * @return The event type as a CSV String.
     */
    public String toString() {
        return toCSV();
    }

    /***************************************************************************
     * Net/FSE handles syslog events differently from non-syslog events.
     * Typically, syslog events have timestamp or IP information in the syslog
     * header. If this method returns true, the syslog header will be maintained
     * by nfse.SyslogThread. If it returns false the header will be discarded.
     * This method should be overridden to return true for any event type that
     * requires the syslog header for obtaining field information needed by
     * Net/FSE (i.e. timestamps and IPs).
     * 
     * @return This stub method returns false, causing the syslog header to be
     *         discarded.
     */
    public boolean isSyslog() {
        return false;
    }

    public boolean isAlert() {
        return false;
    }

    public String getAlertMessage() {
        return "";
    }

    public String toXML() {
        return "<"+getTypeName()+" sensorid=\"" + getSensorID() + "\">toXML() method not implemented for type " + getTypeID()
                + "</"+getTypeName()+">";
    }

	/**
	 * @param typeName the typeName to set
	 */
	public void setTypeName(String typeName) {
		this.typeName = typeName;
	}

	/**
	 * @param typeID the typeID to set
	 */
	public void setTypeID(int typeID) {
		this.typeID = typeID;
	}

	/**
	 * @param sensorID the sensorID to set
	 */
	public void setSensorID(int sensorID) {
		this.sensorID = sensorID;
	}

	/**
	 * @return the sensorID
	 */
	public int getSensorID() {
		return sensorID;
	}

	/**
	 * @param initialString the initialString to set
	 */
	public void setInitialString(String initialString) {
		this.initialString = initialString;
	}

	/**
	 * @return the initialString
	 */
	public String getInitialString() {
		return initialString;
	}

	/**
	 * @param timestamp the timestamp to set
	 */
	public void setTimestamp(Timestamp timestamp) {
		this.timestamp = timestamp;
	}

	/**
	 * @return the timestamp
	 */
	public Timestamp getTimestamp() {
		return timestamp;
	}

	/**
	 * @param srcAddr the srcAddr to set
	 */
	public void setSrcAddr(String srcAddr) {
		this.srcAddr = srcAddr;
	}

}
